package com.nageoffer.onecoupon.framework.idempotent;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ArrayUtil;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Optional;

/**
 * SpEL 表达式解析工具
 */
public final class SpELUtil {

    /**
     * 校验并返回实际使用的 spEL 表达式
     *
     * @param spEl spEL 表达式
     * @return 实际使用的 spEL 表达式
     */
    public static Object parseKey(String spEl, Method method, Object[] contextObj) {
        // 定义 SpEL 表达式的标志符（如 #param 或 T(com.example.Class)）
        List<String> spELFlag = ListUtil.of("#", "T(");
        // 检查输入字符串是否包含任一标志符
        Optional<String> optional = spELFlag.stream().filter(spEl::contains).findFirst();
        if (optional.isPresent()) {
            // 如果是 SpEL 表达式，调用 parse 方法解析
            return parse(spEl, method, contextObj);
        }
        // 否则直接返回原字符串
        return spEl;
    }

    /**
     * 转换参数为字符串
     *
     * @param spEl       spEl 表达式
     * @param contextObj 上下文对象
     * @return 解析的字符串值
     */
    public static Object parse(String spEl, Method method, Object[] contextObj) {
        // 1. 获取方法参数的名称（依赖编译时保留参数名或 -parameters 编译选项）
        DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
        String[] params = discoverer.getParameterNames(method);

        // 2. 创建 SpEL 解析器和上下文
        ExpressionParser parser = new SpelExpressionParser();
        StandardEvaluationContext context = new StandardEvaluationContext();

        // 3. 将方法参数名与传入的 contextObj 值绑定到上下文
        if (ArrayUtil.isNotEmpty(params)) {
            for (int len = 0; len < params.length; len++) {
                context.setVariable(params[len], contextObj[len]);
            }
        }

        // 4. 解析表达式并返回结果
        Expression exp = parser.parseExpression(spEl);
        return exp.getValue(context);
    }
}
